package br.com.medvagas.comum.excecao;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.el.ELException;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import br.com.medvagas.comum.util.JSFMensagem;
import br.com.medvagas.comum.util.UtilJSF;

public class TratadorExcecao2 extends ExceptionHandlerWrapper {

	private static final Log LOG = LogFactory.getLog(TratadorExcecao2.class);
	private static final String MASCARA_DATA = "dd/MM/yyyy";
	
	private final ExceptionHandler wrapped;

	public TratadorExcecao2(ExceptionHandler wrapped) {
		this.wrapped = wrapped;
	}

	@Override
	public ExceptionHandler getWrapped() {
		return this.wrapped;
	}

	@Override
	public void handle() throws FacesException {
		for (Iterator<ExceptionQueuedEvent> it = getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();) {

			boolean isExcecaoRegraNegocio = false;
			
			Throwable t = it.next().getContext().getException();
			List<Throwable> lstThrowable = ExceptionUtils.getThrowableList(t);
			if (lstThrowable != null) {
				for (Throwable throwable : lstThrowable) {
					if (throwable instanceof ExcecaoRegraNegocio) {
						ExcecaoRegraNegocio ern = (ExcecaoRegraNegocio) throwable;
						JSFMensagem.addMenssagemErro(ern.getMessage());
						isExcecaoRegraNegocio = true;
					}
				}
			}
			
			if (!isExcecaoRegraNegocio) {
				String codigoExcecao = getCodigoExcecao();
				String mensagem = JSFMensagem.addMenssagemFatal("INFRA_001", codigoExcecao);
				
				String stackTrace = mensagem + " - " + ExceptionUtils.getFullStackTrace(t);
				LOG.error(stackTrace);
				System.out.println(stackTrace);
			}
			
			FacesContext facesContext = FacesContext.getCurrentInstance();
			Application application = facesContext.getApplication();
			NavigationHandler navigationHandler = application.getNavigationHandler();
			navigationHandler.handleNavigation(facesContext, null, null);
			facesContext.renderResponse();
		}
		
	}
	
	/**
	 * Recupera um codigo unico a ser utilizado para identificar uma determinada excecao. 
	 * Este codigo eh calculado pela diferenca em milisegundos entre a data do primeiro 
	 * dia do mes corrente e a data atual
	 * @return codigo da excecao
	 */
	protected String getCodigoExcecao() {
		String codigo = null;
		
		SimpleDateFormat formatador = new SimpleDateFormat(MASCARA_DATA);
		
		Date dataAtual = new Date();
		String dataCorrente = formatador.format(dataAtual);
		
		String mes = dataCorrente.substring(3, 5);
		String ano = dataCorrente.substring(6, 10);
		
		try {
			Date dataPrimeiroDiaMes = formatador.parse("01/" + mes + "/" + ano);
			codigo = String.valueOf(dataAtual.getTime() - dataPrimeiroDiaMes.getTime());
		} catch (Exception e) {
			LOG.error("Falha ao tentar gerar o codigo do erro da operacao do usuario", e);
		}
		
		return codigo;
	}
	

	
	public void handle2() throws FacesException {
		for (Iterator<ExceptionQueuedEvent> it = getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();) {
			Throwable t = it.next().getContext().getException();
			while ((t instanceof FacesException || 
//					t instanceof EJBException || 
					t instanceof ELException) && t.getCause() != null) {
				t = t.getCause();
			}
			if (t instanceof FileNotFoundException
//					|| t instanceof HandledException
					|| t instanceof ViewExpiredException) {
				FacesContext facesContext = FacesContext.getCurrentInstance();
				ExternalContext externalContext = facesContext.getExternalContext();
				Map<String, Object> requestMap = externalContext.getRequestMap();
				try {
//					LOG.info("{}: {}", t.getClass().getSimpleName(), t.getMessage());
					String message;
					if (t instanceof ViewExpiredException) {
						final String viewId = ((ViewExpiredException) t).getViewId();
						message = "View is expired. <a href='/ifos" + viewId + "'>Back</a>";
					} else {
						message = t.getMessage(); // beware, don't leak internal info!
					}
					requestMap.put("errorMsg", message);
					try {
						externalContext.dispatch("/error.jsp");
					} catch (final IOException e) {
//						LOG.error("Error view '/error.jsp' unknown!", e);
					}
					facesContext.responseComplete();
				} finally {
					it.remove();
				}
			}
		}
		getWrapped().handle();
	}
}